﻿using BootstrapBlazor.Components;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace zy_simu.Data
{
    public class DeviceSnap
    {
        // gpio description table
        public ZyIOsDefTable? gpio = null;                    // device state
        //public ZyFuncsDefTable? funcs = null;

        //private int dev_state = 0;
        // communication command flag: 
        private const byte COMM_CMD_DBG_LOG = 0x18;        // communication command: debug cmd: print log
        private const byte COMM_CMD_DBG_SNAP = 0x19;       // communication command: debug cmd: snap
        private const byte COMM_CMD_DBG_CFG = 0x1a;        // communication command: debug cmd: get device functions, IOs, Parameters and state config
        // communication handle and buffer
        private IEmuComm? comm = null;
        private byte[] recv_buf = new byte[1024 * 2];
        private int recv_cnt = 0;

        // m0/cat1 simulator process handle
        private Process? m0_process = null;
        private Process? cat1_process = null;

        public readonly int TASK_PERIOD = 50;
        public readonly Dictionary<string, string> button_icons = new() {
            { "SET", "fas fa-gear" },
            { "PLUS", "fas fa-plus" },
            { "MINUS", "fas fa-minus" },
            { "LIGHT", "fas fa-lightbulb" },
            { "FUNC", "fas fa-cloud-rain" },
            { "SWITCH", "fas fa-retweet" },
        };

        public uint dev_type { get; set; } = 0;       // 设备类型
        // display definition table
        public int disp_panel = 1;
        // gpios definition table
        public ZyIOsDefTable? gpio_tb = null;
        // keys definition
        public string[] keys_def = new string[] { "SET", "PLUS", "MINUS" };
        // 显示方式描述,
        public int disp_buff_size = 5;
        public int disp_digital_cnt = 3;
        public int disp_item_d_start = 0;
        // 图标定义和控制, {3, 0x10}表示由显示buf[3]的bit3控制; { 0, 0x0 } -- 表示无效
        public byte[,] led_icon_def = new byte[,] {
            { 3, 0x01}, { 3, 0x02}, { 3, 0x04}, { 3, 0x08},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
            { 3, 0x10}, { 3, 0x20}, { 3, 0x40}, { 4, 0x01},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
            { 4, 0x02}, { 4, 0x04}, { 4, 0x08}, { 4, 0x10},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
            { 4, 0x00}, { 4, 0x00}, { 4, 0x20}, { 4, 0x40},  		// disp_item_drip, disp_item_pow, disp_item_dot, disp_item_minus
        };
        // 小数点 和 负号  
        //public int[] led_dot_def = new int[] { 4, 0x20 };
        //public int[] led_minus_def = new int[] { 4, 0x40 };

        // parameters display name, minimum value, maxmum value, map, and value
        public ZqmParamsTable[]? pms_tb = null;
        //public string[]? pms_name = null;
        //public short[]? pms_min = null;
        //public short[]? pms_max = null;
        //public byte[]? pms_map = null;
        public short[]? pms = null;
        // 设备参数描述集合
        public string[] pms_des =
        {
            "温度设定值, ℃",
            "温度设定最小值, ℃" ,
            "温度设定最大值, ℃" ,
            "温度报警延迟, min",
            "高温报警温度, ℃",
            "低温报警温度, ℃",
            "上电报警延时, hour",

            "温度上回差, .1℃",
            "温度下回差, .1℃",
            "传感器故障开机, min",
            "传感器故障关机, min",
            "显示温度补偿, .1℃",
            "化霜解锁时间, hour",
            "最短停机时间, min",
            "开停机补偿, ℃",
            "压缩机上电后的延时, 分钟",
            "压机强制运行, hour",

            "自然化霜/压机保护周期, hour",
            "自然化霜/压机保护时间, min",
            "热除霜周期, hour",
            "除霜排水时间, min",
            "热除霜预冷时间, min",
            "热除霜退出温度, ℃",
            "热除霜上限时间, min",
            "强制除霜, min",

            "故障代码",
            "4G信号强度",
            "电池电量查看, 0-100, %",
            "软件版本",

            "密码配置",
            "蜂鸣器开关",
            "显示模式",
            "拉温模式",
            
            "非营业模块开始时间, H",
            "非营业模块结束时间, H",
            "非营业模块智能模式, N",
            "非营业模式设定温度, ℃",

    };
        // dbg state table
        public ZyStates st = new ZyStates();                    // device state
        private byte[] st_buf = new byte[Marshal.SizeOf<ZyStates>()]; // ZyStates buffer
        // 设备状态描述
        public readonly string[] st_name = {"d_temp", "m_temp", "load_vol", "load_cur", "load_pow", "vbat", "alarm",
            "fan_state", "light_state", "heater_state", "ble", "_4g", "wifi", "_4g_strength",
            "ctrl_mode", "ctrl_state", "ctrl_switch",
            "comp_mode", "comp_state", "temp_reach_region", "power_up_6h", "comp_on_timer", "comp_on_timer_acc", "comp_off_timer", "sensor_fault_on", "sensor_fault_off", "comp_cc",
            "defrost_timer", "defrost_d_temp", "defrost_m_temp", "defrost_drain_timer", "defrost_lock_timer", "door1_timer", "door1_count", "humman",
            "alarm_ad_timer", "cat1_heart"};
        public readonly string[] st_des =
        {
            "显示温度",
            "测量温度",
            "负载电压",
            "负载电流",
            "负载功率",
            "电池电压 mv",

            "报警项目",
            "风机工作状态",
            "照明灯状态",
            "加热器启停状态",

            "蓝牙工作状态",
            "4G ",
            "wifi",
            "4G信号强度",

            "控制器工作模式",
            "控制器工作状态",
            "控制器开关",

            "压机运行模式",
            "压机运行状态",
            "温度到达过TS+-2区间",
            "开机到达6小时",

            "压机本次运行时间",
            "压机累计运行时间",
            "压机关机时间",
            "故障开机时间",
            "故障关机时间",
            "强制开机时间",

            "除霜运行时间",
            "除霜传感器显示温度",
            "除霜传感器测量温度",
            "除霜排水时间",
            "除霜后温度锁定计时",

            "门开计时",
            "门开计次",
            "人流量计数",

            "温度报警延迟计时",
            "Cat1心跳计时追踪",
        };

        // key buffer
        public uint[] k_state;
        // display buffer
        public byte[] disp_hw_buf;

        // GPIO value
        public uint gpioa = 0;
        public uint gpiob = 0;
        // GPIO I/O mode, 1表示输出
        public uint gpioa_d = 0;
        public uint gpiob_d = 0;
        // ADC value
        public ushort[] adc = new ushort[4];


        private SimuCfg cfg;
        public DeviceSnap()
        {
        }

        private EmuCommPipe virtual_port1 = default!;
        private EmuCommPipe virtual_port2 = default!;
        public async Task<bool> Start(SimuCfg config)
        {
            virtual_port1 = new EmuCommPipe();
            virtual_port2 = new EmuCommPipe();
            this.cfg = config;
            // 根据设备或者功能 判断是监控m0还是cat1
            if (cfg.m0_mode == "仿真")        // 启动M0仿真设备
                M0PowerOn();
            else if (cfg.m0_mode == "外设")   // 挂真实设备，启动控制台接收log
                KgConsoleManager.Show();
            else if(cfg.cat1_mode == "仿真")  // 无M0控制cat1，启动单cat1仿真设备，一般是纯定位器等
                Cat1PowerOn();

            // 等待子进程启动
            await Task.Delay(100);
            // 启动模拟器监视通讯口
            if (cfg.mon_mode == "串口")
            {
                if (cfg.mon_port == "虚拟接口-1")
                    comm = virtual_port1;
                else if (cfg.mon_port == "虚拟接口-2")
                    comm = virtual_port2;
                else if (cfg.mon_port.StartsWith("COM"))
                    comm = new EmuCommUart(cfg.mon_port);
            }
            else if (cfg.mon_mode == "蓝牙")
            {
                comm = new EmuCommBle(cfg.mon_port.Replace(":", ""));
            }
            if(comm == null)
                return false;
            if(!(await comm.Open()))
                return false;

            //// 等待建立通讯, 2s超时
            //await Task.Run(() =>
            //{
            //    for (int i = 0; i < 100 && dev_state == 0; System.Threading.Thread.Sleep(20), i++) Recv();
            //});
            //if (dev_state == 0) return false;   // 建立通讯失败

            // 获取设备基本参数, TODO 尝试3次
            await Task.Delay(100);
            for(int retry = 0; retry < 3 && gpio_tb == null; retry++)
            {
                QueryDeviceCfg();
                // 等待接收设备基本参数, 1000ms超时
                await Task.Run(() =>
                {
                    for (int i = 0; i < 50 && gpio_tb == null; System.Threading.Thread.Sleep(20), i++) Recv();
                });
            }
            if (gpio_tb == null)
            {
                await Stop();
                return false;
            }
            switch (disp_panel)
            {
                case 1: // integral display panel, 3 key, 5 grid, 7 seg, 12 icon, tm1618 driver;
                    {
                        keys_def = new string[] { "SET", "PLUS", "MINUS" };
                        disp_buff_size = 5;
                        disp_digital_cnt = 3;
                        disp_item_d_start = 0;
                        led_icon_def = new byte[,] {
                            {3, 0x01}, {3, 0x02}, {3, 0x04}, {3, 0x08},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
                            {3, 0x10}, {3, 0x20}, {3, 0x40}, {4, 0x01},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
                            {4, 0x02}, {4, 0x04}, {4, 0x08}, {4, 0x10},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
                            {4, 0x00}, {4, 0x00}, {4, 0x20}, {4, 0x40},  		// disp_item_drip, disp_item_pow, disp_item_dot, disp_item_minus
                        };
                    }
                    break;
                case 2: // split display panel, 1 key, 3 grid, 7 seg, 2 icon, tm1628 driver;
                    {
                        // 键盘描述
                        keys_def = new string[] { "SET" };
                        // 显示方式描述,
                        disp_buff_size = 3;
                        disp_digital_cnt = 2;
                        disp_item_d_start = 1;
                        // 图标定义和控制, {3, 0x10}表示由显示buf[3]的bit3控制; { 0, 0x0 } -- 表示无效
                        led_icon_def = new byte[,] {
                            {0, 0x01}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
                            {0, 0x04}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
                            {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
                            {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x02},  		// disp_item_drip, disp_item_x, disp_item_dot, disp_item_minus
                        };
                    }
                    break;
                case 3: // split display panel, 2 key, 3 grid, 7 seg, 2 icon, tm1628 driver;
                    {
                        keys_def = new string[] { "SWITCH", "SET" };
                        // 显示方式描述,
                        disp_buff_size = 3;
                        disp_digital_cnt = 2;
                        disp_item_d_start = 0;
                        // 图标定义和控制, {3, 0x10}表示由显示buf[3]的bit3控制; { 0, 0x0 } -- 表示无效
                        led_icon_def = new byte[,] {
                            {1, 0x80}, {2, 0x80}, {0, 0x00}, {0, 0x00},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
                            {0, 0x04}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
                            {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
                            {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x80},  		// disp_item_drip, disp_item_x, disp_item_dot, disp_item_minus
                        };
                    }
                    break;
                case 4: // integral display panel, 0 key, 5 grid, 7 seg, 12 icon, tm1618 driver;
                    {
                        keys_def = new string[] {};
                        disp_buff_size = 5;
                        disp_digital_cnt = 3;
                        disp_item_d_start = 0;
                        led_icon_def = new byte[,] {
                            {3, 0x01}, {3, 0x02}, {3, 0x04}, {3, 0x08},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
                            {3, 0x10}, {3, 0x20}, {3, 0x40}, {4, 0x01},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
                            {4, 0x02}, {4, 0x04}, {4, 0x08}, {4, 0x10},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
                            {4, 0x00}, {4, 0x00}, {4, 0x20}, {4, 0x40},  		// disp_item_drip, disp_item_pow, disp_item_dot, disp_item_minus
                        };
                    }
                    break;
                case 5: // integral display panel, 4 key, 4 grid, 8seg, 8icon, m582 driver; 
                    {
                        keys_def = new string[] { "SET", "PLUS", "MINUS", "FUNC" };
                        // 显示方式描述,
                        disp_buff_size = 4;
                        disp_digital_cnt = 3;
                        disp_item_d_start = 0;
                        // 图标定义和控制, {3, 0x10}表示由显示buf[3]的bit3控制; { n, 0x0 } -- 表示无效
                        led_icon_def = new byte[,] {
                            {3, 0x01}, {3, 0x00}, {3, 0x04}, {3, 0x00},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
	                        {3, 0x00}, {3, 0x00}, {3, 0x08}, {3, 0x40},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
	                        {3, 0x00}, {3, 0x80}, {3, 0x00}, {3, 0x00},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
                            {3, 0x10}, {3, 0x00}, {1, 0x80}, {2, 0x80},  		// disp_item_drip, disp_item_x, disp_item_dot, disp_item_minus
                        };
                    }
                    break;
                case 6: // integral display panel(圆角), 3 key, 4 grid, 8 seg, 6 icon, tm1618 driver;  
                    {
                        // 键盘描述
                        keys_def = new string[] { "SET", "PLUS", "MINUS" };
                        // 显示方式描述,
                        disp_buff_size = 4;
                        disp_digital_cnt = 3;
                        disp_item_d_start = 0;
                        // 图标定义和控制, {3, 0x10}表示由显示buf[3]的bit3控制; { 0, 0x0 } -- 表示无效
                        led_icon_def = new byte[,] {
                            {3, 0x10}, {3, 0x20}, {0, 0x00}, {0, 0x00},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
                            {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
                            {3, 0x08}, {3, 0x04}, {0, 0x00}, {0, 0x00},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
                            {0, 0x00}, {3, 0x40}, {1, 0x80}, {3, 0x80},  		// disp_item_drip, disp_item_cool, disp_item_dot, disp_item_minus
                        };
                    }
                    break;
                case 7: // split display panel(斜体), 1 key, 2 grid, 8 seg, 1 icon, tm1628 driver;
                    {
                        // 键盘描述
                        keys_def = new string[] { "SET" };
                        // 显示方式描述,
                        disp_buff_size = 2;
                        disp_digital_cnt = 2;
                        disp_item_d_start = 0;
                        // 图标定义和控制, {3, 0x10}表示由显示buf[3]的bit3控制; { 0, 0x0 } -- 表示无效
                        led_icon_def = new byte[,] {
                            {1, 0x80}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
                            {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
                            {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
                            {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x80},  		// disp_item_drip, disp_item_x, disp_item_dot, disp_item_minus
                        };
                    }
                    break;
                case 8: // integral display panel, 4 key, 5 grid, 7 seg, 12 icon, tm1618 driver;
                    {
                        keys_def = new string[] { "SET", "PLUS", "MINUS", "LIGHT" };
                        disp_buff_size = 5;
                        disp_digital_cnt = 3;
                        disp_item_d_start = 0;
                        led_icon_def = new byte[,] {
                            {3, 0x01}, {3, 0x02}, {3, 0x04}, {3, 0x08},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
                            {3, 0x10}, {3, 0x20}, {3, 0x40}, {4, 0x01},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
                            {4, 0x02}, {4, 0x04}, {4, 0x08}, {4, 0x10},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
                            {4, 0x00}, {4, 0x00}, {4, 0x20}, {4, 0x40},  		// disp_item_drip, disp_item_pow, disp_item_dot, disp_item_minus
                        };
                    }
                    break;
            }

            k_state = new uint[keys_def.Length];
            disp_hw_buf = new byte[disp_buff_size];
            // GPIO value
            gpioa = 0;
            gpiob = 0;
            // GPIO I/O mode, 1表示输出
            gpioa_d = 0;
            gpiob_d = 0;
            // ADC value
            adc = new ushort[4];
            return true;
        }
        public async Task Stop()
        {
            M0PowerOff();
            Cat1PowerOff();
            if (comm != null)
            {
                await comm.Close();
                comm = null;
            }
        }
        public void WriteGPIO(uint gpio, bool value)
        {
            uint io = gpio & 0x7fffffff;
            if (io == 0) return;
            else if (io == gpio)
                gpioa = value ? (gpioa | io) : (gpioa & (~io));
            else
                gpiob = value ? (gpiob | io) : (gpiob & (~io));
        }
        public bool ReadGPIO(uint gpio)
        {
            uint io = gpio & 0x7fffffff;
            if (io == 0) return false;
            else if (io == gpio)
                return ((gpioa & io) != 0);
            else
                return ((gpiob & io) != 0);
        }
        private void M0PowerOn()
        {
            if (m0_process != null) return;
            ProcessStartInfo startInfo = new ProcessStartInfo("m0.exe");
            // 不从操作系统的shell启动，这样继承父进程的标准流和匿名管道等资源
            startInfo.UseShellExecute = false;
            // 开启自己的控制台来输出log
            startInfo.CreateNoWindow = false;

            // 配置m0的4个串口
            for (int i = 0; i < 4; i++)
            {
                string port = "NULL";
                if (cfg.m0_port[i] == "虚拟接口-1")
                    port = virtual_port1.GetClientPort();
                else if (cfg.m0_port[i] == "虚拟接口-2")
                    port = virtual_port2.GetClientPort();
                else if (cfg.m0_port[i].StartsWith("COM"))
                {
                    if (cfg.m0_port[i].Length <= 4) port = cfg.m0_port[i];  // if < COM9
                    else port = string.Format("\\\\.\\{0}", cfg.m0_port[i]);    // windows 设备要求> com9, 使用\\.\comxx这种格式
                }
                startInfo.ArgumentList.Add(port);
            }
            // 启动M0
            m0_process = Process.Start(startInfo);
        }
        private void M0PowerOff()
        {
            if (m0_process != null)
            {
                m0_process.Kill();
                m0_process.Close();
                m0_process = null;
            }
        }
        // Start/stop cat1 simulator
        public void Cat1PowerOn()
        {
            if (cat1_process != null) return;
            if (cfg.cat1_mode != "仿真") return;
            ProcessStartInfo startInfo = new ProcessStartInfo("cat1.exe");
            // 不从操作系统的shell启动，这样继承父进程的标准流和匿名管道等资源
            startInfo.UseShellExecute = false;
            // 开启自己的控制台来输出log
            startInfo.CreateNoWindow = false;

            // 配置cat1的2个串口
            for (int i = 0; i < 2; i++)
            {
                string port = "NULL";
                if (cfg.cat1_port[i] == "虚拟接口-1")
                    port = virtual_port1.GetServerPort();
                else if (cfg.cat1_port[i] == "虚拟接口-2")
                    port = virtual_port2.GetServerPort();
                else if (cfg.cat1_port[i].StartsWith("COM"))
                {
                    if (cfg.cat1_port[i].Length <= 4) port = cfg.cat1_port[i];  // if < COM9
                    else port = string.Format("\\\\.\\{0}", cfg.cat1_port[i]);    // windows 设备要求> com9, 使用\\.\comxx这种格式
                }
                startInfo.ArgumentList.Add(port);
            }
            // 启动Cat1
            cat1_process = Process.Start(startInfo);
            // 如果通道是为子进程创建的，这里关闭多余的handle。
            if (cfg.cat1_port[0] == "虚拟接口-1")
            {
                virtual_port1.Close();
            }
            if (cfg.cat1_port[0] == "虚拟接口-2")
            {
                virtual_port2.Close();
            }

        }
        public void Cat1PowerOff()
        {
            if (cat1_process != null)
            {
                cat1_process.Kill();
                cat1_process.Close();
                cat1_process = null;
            }
        }






        private short pm_mod_value = 0;
        private int pm_mod_idx = -1;
        public void ChangePmTable(int idx, short value)
        {
            if (idx >= 0 && idx < pms_tb.Length)
            {
                pm_mod_idx = idx;
                pm_mod_value = value;
            }
            else { pm_mod_idx = -1;}
        }
        private int st_mod_value;
        private int st_mod_idx = 0;
        public void ChangeStTable(int idx, int value)
        {
            System.Reflection.FieldInfo[] fields = st.GetType().GetFields();
            //fields[idx].SetValue(st, value);
            if (idx >= 0 && idx < fields.Length)
            {
                st_mod_idx = idx;
                st_mod_value = value;
            }
            else { st_mod_idx = -1; }
        }
        private bool is_gpio_changed = true;
        private bool is_adc_changed = true;
        public void ChangeGPIO(bool IsChanged)
        {
            is_gpio_changed = IsChanged;
        }
        private byte last_key = 0;
        private byte key = 0;
        public void ChangeKey(byte key)
        {
            this.key = key;
        }


        public void Recv()
        {
            recv_cnt += comm.Recv(recv_buf, recv_cnt, recv_buf.Length - recv_cnt);
            if(recv_cnt < 4)
                return;
            //Array.Copy(buf, 0, recv_buf, recv_cnt, cnt);
            //recv_cnt += cnt;
            while (true) // 处理连续多帧
            {
                if (recv_buf[0] != 0xaa) // 帧异常，清空
                    break;
                if (recv_cnt < 4) // 数据不足，继续收
                    return;
                CommPkg pkg = new(ref recv_buf);
                if (pkg.len > recv_cnt) // 数据不足，继续收
                    return;
                if (0 != CommPkg.GetChecksum(recv_buf, pkg.len)) // 帧异常
                    break;
                switch (pkg.cmd)
                {
                    case DeviceSnap.COMM_CMD_DBG_LOG: // debug 字符串
                        //if (dev_state == 0) dev_state = 1;  // 接收到信息表示控制器模拟器已经启动完毕，可以发送查询信息
                        RecvDbgPrint(recv_buf[4..pkg.len]);
                        break;
                    case DeviceSnap.COMM_CMD_DBG_SNAP: // snapshot 数据包
                        RecvSnapshot(recv_buf[4..pkg.len]);
                        break;
                    case DeviceSnap.COMM_CMD_DBG_CFG:
                        RecvDeviceCfg(recv_buf[4..pkg.len]);
                        break;
                    default:
                        recv_cnt = pkg.len; // 数据异常，假设=pkg.len，立刻退出，让后面自动清零
                        break;
                }

                recv_cnt -= pkg.len;    // 转到下一帧
                if (recv_cnt > 0)
                    Array.Copy(recv_buf, pkg.len, recv_buf, 0, recv_cnt);
                else //处理完成所有帧
                    break;
            }
            recv_cnt = 0;
            return;
        }

        private void Send(byte cmd, byte[] buf, int len)
        {
            byte[] tx_buf = new byte[CommPkg.GetHeadSize() + len];
            CommPkg pkg = new(ref tx_buf);
            pkg.flag = 0xaa;
            pkg.cmd = cmd;
            pkg.len = (ushort)tx_buf.Length;
            pkg.checksum = 0;

            for (int i = 0; i < len; i++) tx_buf[4 + i] = (byte)buf[i];
            pkg.checksum = CommPkg.GetChecksum(tx_buf, (uint)tx_buf.Length);
            //com.Write(tx_buf, 0, tx_buf.Length);
            if(comm != null)
                comm.Send(tx_buf, tx_buf.Length);
        }

        // debug 字符串
        public void RecvDbgPrint(byte[] data)
        {
            string str = Encoding.UTF8.GetString(data, 0, data.Length);
            System.Console.WriteLine(str);
        }
        public bool pms_out_sync = false;
        public bool sts_out_sync = false;
        // snapshot 数据包
        public void RecvSnapshot(byte[] data)
        {
            int offset = 0;
            // unpack pms
            int cnt = data[offset++];
            for (int i = 0; i < cnt; i++)
            {
                int idx = data[offset++];
                pms_tb[idx].val = (short)(data[offset] | (data[offset+1] << 8));
                offset += 2;
            }
            byte[] buf = new byte[pms_tb.Length*sizeof(short)];
            for (int i = 0; i < pms_tb.Length; i++)
            {
                buf[2*i] = (byte)(pms_tb[i].val & 0xFF);
                buf[2*i+1] = (byte)((pms_tb[i].val >> 8) & 0xFF);
            }
            pms_out_sync = (CommPkg.GetChecksum(buf, (uint)buf.Length) != data[offset++]);
            // unpack st
            cnt = data[offset++];
            for (int i = 0; i < cnt; i++)
            {
                int idx = data[offset++];
                st_buf[idx++] = data[offset++];
                st_buf[idx++] = data[offset++];
                st_buf[idx++] = data[offset++];
                st_buf[idx++] = data[offset++];
            }
            sts_out_sync = (CommPkg.GetChecksum(st_buf, (uint)st_buf.Length) != data[offset++]);
            if (cnt > 0) st = KgStreamConvert.BytesToStuct<ZyStates>(st_buf);
            // unpack gpio mode
            cnt = data[offset++];
            if((cnt & 0x01) == 0x01)
            {
                gpioa_d = (uint)(data[offset] | (data[offset + 1] << 8));
                offset += 2;
            }
            if ((cnt & 0x02) == 0x01)
            {
                gpiob_d = (uint)(data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16));
                offset += 3;
            }
            if ((cnt & 0x04) == 0x04)
            {
                gpioa = (uint)(data[offset] | (data[offset + 1] << 8));
                offset += 2;
            }
            if ((cnt & 0x08) == 0x08)
            {
                gpiob = (uint)(data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16));
                offset += 3;
            }
            // unpack key and display buffer
            for(int i = 0; i < k_state.Length; i++)
            {
                k_state[i] = (uint)(data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24));
                offset += 4;
            }
            for (int i = 0; i < disp_hw_buf.Length; i++)
            {
                disp_hw_buf[i] = data[offset++];
            }
        }

        // exchange dbg data with device
        // 接收: 包头DbgPkgbuf[4] + 参数数量i[1] + 参数表(pm_idx[1] + pm_value[2])[i * 3] + 状态数量j[1] + 状态表(st_idx[1] + st_value[4])[j * 5] 
        //	+ GPIO变化(bit0-3表示以下有效, gpioa mode, gpiob mode, gpioa, gpiob)k[1] + GPIO_MODE[5] + GPIO[5]
        // 发送: 包头DbgPkgbuf[5] + 查询命令(0不需查询，1全量查询，2增量查询)q[1] + 参数数量i[1] + 参数表(pm_idx[1] + pm_value[2])[i * 3] + 状态数量j[1] + 状态表(st_idx[1] + st_value[4])[j * 5] 
        //	+ GPIO变化(bit0-5, 表示以下有效, gpioa mode, gpiob mode, gpioa, gpiob, adc, key)k[1] + GPIO_MODE[5] + GPIO[5] + ADC[4] + 键key[1]
        public void ExchangeWithDev(bool isQuestAll)
        {
            byte[] buf = new byte[1024];
            int idx = 0, num = 0;
            // 打包查询device状态，完全回复还是增量回复
            if(pms_out_sync || sts_out_sync) buf[idx] = 2;
            //if (isQuestAll) buf[idx] = 2;
            else buf[idx] = 1;
            idx++;
            // 打包参数修改
            num = idx;
            buf[idx++] = 0;
            if (pm_mod_idx >= 0)
            {
                buf[num] += 1;
                buf[idx++] = (byte)(pm_mod_idx & 0xFF);
                buf[idx++] = (byte)(pm_mod_value & 0xFF);
                buf[idx++] = (byte)((pm_mod_value >> 8) & 0xFF);
                pm_mod_idx = -1;
            }
            // 打包状态修改
            num = idx;
            buf[idx++] = 0;
            if (st_mod_idx >= 0)
            {
                System.Reflection.FieldInfo[] fields = st.GetType().GetFields();
                Type t = fields[st_mod_idx].FieldType;
                if(t == typeof(byte))
                {
                    fields[st_mod_idx].SetValue(st, (byte)st_mod_value);
                }
                else if (t == typeof(short))
                {
                    fields[st_mod_idx].SetValue(st, (short)st_mod_value);
                }
                else if (t == typeof(ushort))
                {
                    fields[st_mod_idx].SetValue(st, (ushort)st_mod_value);
                }
                else
                {
                    fields[st_mod_idx].SetValue(st, st_mod_value);
                }

                byte[] st_buf_mod = KgStreamConvert.Struct2Bytes(st);
                for (int i = 0; i < st_buf_mod.Length; i += 4)
                {
                    if (st_buf_mod[i] != st_buf[i] || st_buf_mod[i+1] != st_buf[i+1] || st_buf_mod[i + 2] != st_buf[i + 2] || st_buf_mod[i + 3] != st_buf[i + 3])
                    {
                        buf[num] += 1;
                        buf[idx++] = (byte)(i);
                        buf[idx++] = st_buf_mod[i];
                        buf[idx++] = st_buf_mod[i + 1];
                        buf[idx++] = st_buf_mod[i + 2];
                        buf[idx++] = st_buf_mod[i + 3];
                    }
                }
                st_mod_idx = -1;
            }
            // 打包Key修改
            num = idx;
            buf[idx++] = 0;
            if (key != 0 || key != last_key)         // 有key或者key全清除，通知设备
            {
                buf[num] |= 0x20;
                buf[idx++] = key;
            }
            last_key = key;
            // 打包GPIO修改
            if(is_gpio_changed)
            {
                buf[num] |= (0x04|0x08);
                buf[idx++] = (byte)(gpioa >> 0);
                buf[idx++] = (byte)(gpioa >> 8);
                buf[idx++] = (byte)(gpiob >> 0);
                buf[idx++] = (byte)(gpiob >> 8);
                buf[idx++] = (byte)(gpiob >> 16);
            }
            // 打包ADC修改
            if (is_adc_changed)
            {
                buf[num] |= 0x10;
                for (int i = 0; i < adc.Length; i++)
                {
                    buf[idx++] = (byte)(adc[i] & 0xff);
                    buf[idx++] = (byte)((adc[i] >> 8) & 0xff);
                }
            }
            Send(DeviceSnap.COMM_CMD_DBG_SNAP, buf, idx);
        }
        public void QueryDeviceCfg()
        {
            byte[] buf = new byte[128];
            //funcs = null;
            Send(DeviceSnap.COMM_CMD_DBG_CFG, buf, 0);
            return;
        }
        private void RecvDeviceCfg(byte[] data)
        {
            int offset = 0;
            // unpack device type, 32bits 
            dev_type = (uint)(data[offset++]);
            dev_type += (uint)(data[offset++] << 8);
            dev_type += (uint)(data[offset++] << 16);
            dev_type += (uint)(data[offset++] << 24);
            //// unpack functions definition table
            //int cnt = data[offset++];
            //Debug.Assert(cnt == Marshal.SizeOf<ZyFuncsDefTable>());
            //funcs_tb = KgStreamConvert.BytesToStuct<ZyFuncsDefTable>(data[offset..(offset + cnt)]);
            //offset += cnt;
            // unpack display panel type
            disp_panel = data[offset++];
            // unpack gpio definition table
            int cnt = data[offset++];
            Debug.Assert(cnt == Marshal.SizeOf<ZyIOsDefTable>());
            gpio_tb = KgStreamConvert.BytesToStuct<ZyIOsDefTable>(data[offset..(offset + cnt)]);
            offset += cnt;
            // unpack pms
            cnt = data[offset++];

            pms_tb = new ZqmParamsTable[cnt];
            int span = Marshal.SizeOf<ZqmParamsTable>();
            for (int i = 0; i < cnt; i++)
            {
                pms_tb[i] = KgStreamConvert.BytesToStuct<ZqmParamsTable>(data[offset..(offset + span)]);
                offset += span;
            }


            //pms_name = new string[cnt];
            //pms_min = new short[cnt];
            //pms_max = new short[cnt];
            //pms_map = new byte[cnt];
            //// dbg parameter table
            //pms = new short[cnt];
            //for (int i = 0; i < cnt; i++)
            //{
            //    pms_map[i] = data[offset++];
            //}
            //for (int i = 0; i < cnt; i++)
            //{
            //    pms_min[i] = (short)(data[offset] | (data[offset + 1] << 8));
            //    offset += 2;
            //}
            //for (int i = 0; i < cnt; i++)
            //{
            //    pms_max[i] = (short)(data[offset] | (data[offset + 1] << 8));
            //    offset += 2;
            //}
            //// 把类似"abc;def;..."这样的数组转换为string[], 并用分号分隔
            //string str = Encoding.UTF8.GetString(data, offset, data.Length - offset);
            //pms_name = str.Split(';');
            //Debug.Assert(pms_name.Length == cnt);
        }

    }



    public enum ZqAlarmFlag         // 报警标志
    {
        ZQ_ALARM_SENSOR = 0x01,         // 温度传感器错误报警, 0 = 无报警， 1 = 报警
        ZQ_ALARM_HUMIDITY = 0x02,       // 湿度传感器错误报警, 0 = 无报警， 1 = 报警
        ZQ_ALARM_H = 0X04,              // 高温报警, 0 = 无报警， 1 = 报警
        ZQ_ALARM_L = 0X08,              // 低温报警, 0 = 无报警， 1 = 报警
        ZQ_ALARM_POW = 0X10,            // 断电报警, 0 = 无报警， 1 = 报警
        ZQ_ALARM_VBAT_LOW = 0X20,       // 电池电压低报警, 0 = 无报警， 1 = 报警
        ZQ_ALARM_DOOR_OPEN = 0X40,      // 门开报警, 0 = 无报警， 1 = 报警
        ZQ_ALARM_DEFROST_SENSOR = 0X80,	// 化霜传感器错误报警, 0 = 无报警， 1 = 报警
    }


    //// 设备配置描述, 功能描述, IO描述, 参数描述, 状态表描述
    //// 成员必须加public, 不然和dll交互出错
    //[StructLayout(LayoutKind.Sequential, Pack = 4)]
    //public class ZyFuncsDefTable
    //{
    //    private uint funcs = 0;
    //    public uint mainboard              // mainboard type. 1: 582+8850, 2: 582+8910, 3: 582-old/md/hsq, 4: 582(zy326)+8850, 5: 8850
    //    {
    //        get { return (funcs & 0x0f); }
    //        set { funcs = (uint)((funcs & ~0x0f) | (value & 0x0f)); }
    //    }
    //    public uint disp_panel             // display panel type. 1: integral display panel, 2: split display panel(1 key); 3: split display panel(2 key); 4: integral display panel(0 key); 
    //    {
    //        get { return ((funcs & 0xf0) >> 4); }
    //        set { funcs = (uint)((funcs & ~0xf0) | ((value & 0x0f) << 4)); }
    //    }
    //    public uint tem_ctrl               // temperature controller type. refer ZqCtrlMode, cool = CTRL_MODE_COOL; freeze = CTRL_MODE_FREEZE; heater = CTRL_MODE_HOT, may multi functions, ex. cool | freeze | heater
    //    {
    //        get { return ((funcs & 0x0f00) >> 8); }
    //        set { funcs = (uint)((funcs & ~0x0f00) | ((value & 0x0f) << 8)); }
    //    }

    //    public uint ble                    // BLE function
    //    {
    //        get { return ((funcs & 0x10000) >> 16); }
    //        set { funcs = (uint)((funcs & ~0x10000) | ((value & 0x01) << 16)); }
    //    }
    //    public uint hard_switch         // hard switch function(local system switch)
    //    {
    //        get { return ((funcs & 0x20000) >> 17); }
    //        set { funcs = (uint)((funcs & ~0x20000) | ((value & 0x01) << 17)); }
    //    }
    //    public uint soft_switch         // soft switch function
    //    {
    //        get { return ((funcs & 0x40000) >> 18); }
    //        set { funcs = (uint)((funcs & ~0x40000) | ((value & 0x01) << 18)); }
    //    }
    //    public uint door1               // door1 function
    //    {
    //        get { return ((funcs & 0x80000) >> 19); }
    //        set { funcs = (uint)((funcs & ~0x80000) | ((value & 0x01) << 19)); }
    //    }
    //    public uint door2               // door2 function
    //    {
    //        get { return ((funcs & 0x100000) >> 20); }
    //        set { funcs = (uint)((funcs & ~0x100000) | ((value & 0x01) << 20)); }
    //    }
    //    public uint human_ir            // infrared human detection function
    //    {
    //        get { return ((funcs & 0x200000) >> 21); }
    //        set { funcs = (uint)((funcs & ~0x200000) | ((value & 0x01) << 21)); }
    //    }
    //    public uint battery             // battery function
    //    {
    //        get { return ((funcs & 0x400000) >> 22); }
    //        set { funcs = (uint)((funcs & ~0x400000) | ((value & 0x01) << 22)); }
    //    }
    //    public uint pow_meter           // power meter function
    //    {
    //        get { return ((funcs & 0x800000) >> 23); }
    //        set { funcs = (uint)((funcs & ~0x800000) | ((value & 0x01) << 23)); }
    //    }
    //    public uint defrost             // Solenoid valve / heater defrost
    //    {
    //        get { return ((funcs & 0x1000000) >> 24); }
    //        set { funcs = (uint)((funcs & ~0x1000000) | ((value & 0x01) << 24)); }
    //    }
    //};

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public class ZyIOsDefTable
    {
        public uint uart0_tx;          // UART0 TX
        public uint uart0_rx;          // UART0 RX
        public uint uart1_tx;          // UART1 TX
        public uint uart1_rx;          // UART1 RX
        public uint uart2_tx;          // UART2 TX
        public uint uart2_rx;          // UART3 RX
        public uint uart3_tx;          // UART3 TX
        public uint uart3_rx;          // UART3 RX
        public uint periph_pow;        // 外设电源控制
        public uint cat1;              // cat1(通讯模块)控制脚
        public uint motor;             // 压机控制脚
        public uint fan;               // 蒸发风机控制脚
        public uint condenser_fan;     // 冷凝风机控制脚
        public uint heater;            // 制热控制脚
        public uint light;             // 照明控制脚
        public uint melt;              // 化霜加热/电磁阀控制脚
        public uint buzzor;            // 蜂鸣器
        public uint det_12v;           // 电源侦测脚
        public uint det_sys_switch;    // 系统开关侦测脚
        public uint det_door1;         // 门1侦测脚
        public uint det_door2;         // 门2侦测脚
        public uint det_human;         // 红外人流侦测脚
        public uint dis_dio;           // 显示驱动spi数据线
        public uint dis_clk;           // 显示驱动模拟spi时钟线
        public uint dis_stb;           // 显示驱动使能脚
        public uint ntc1_adc;          // 传感器1
        public uint ntc2_adc;          // 传感器2
        public uint batt_adc;          // 电池电压侦测脚
        public uint batt_chrg;         // 电池侦测/充电脚
        public uint batt_stdby;     	// 电池待机脚

        public ZyIOsDefTable()
        {

        }
    };



    // 设备状态描述 - 状态结构
    // 成员必须加public, 不然和dll交互出错
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public class ZyStates
    {
        // 温度state
        public short d_temp;                // 显示温度
        public short m_temp;                // 测量温度
        public short load_vol;              // 负载电压
        public short load_cur;              // 负载电流
        public short load_pow;              // 负载功率
        public short vbat;                  // 电池电压 mv, 0 - 4200, =NUM_INVALID_WORD 表示无电池

        public byte alarm;				    // 报警
        public byte fan_state;              // 风机工作状态
        public byte light_state;		    // 照明灯状态
        public byte heater_state;           // 加热器启停状态

        public byte ble;                    // 蓝牙工作状态
        public byte _4g;                    // "4G ",
        public byte wifi;                   // "wifi",
        public byte _4g_strength;           // "4G信号强度",
        // 控制器state
        public byte ctrl_mode;              // 控制器工作模式: 1 - 冷藏, 2 - 冷冻, 3 - 加热, 4 - 节能?
        public byte ctrl_state;             // 控制器当前实际工作状态: 0-关闭, 1-开启
        public byte ctrl_switch;            // 控制器开关
        // 压机state
        public byte comp_mode;              // 压机运行模式, 参见enum ZyCompMode, 可能多个mode组合，但是当前实际按优先级运行
        public byte comp_state;             // 压机启停状态, 真实状态还要参见mode, 比如压机保护模式下, state=1, 并没有启动压机, 只是闪灯.
        public byte temp_reach_region;      // 温度到过达TS+-2区间
        public ushort power_up_6h;		    // 上电6小时计时

        public int comp_on_timer;           // 压机本次运行时间
        public int comp_on_timer_acc;       // 压机累计运行时间
        public int comp_off_timer;          // 压机持续关机时间
        public int sensor_fault_on;        // 故障制冷开机时间 c3
        public int sensor_fault_off;       // 故障制冷关机时间 c4
        public int comp_cc;		            // 强制开机时间
        // 除霜state
        //public int defrost_state;           // 除霜工作状态
        public int defrost_timer;           // 除霜运行时间
        public short defrost_d_temp;        // 除霜传感器显示温度
        public short defrost_m_temp; 		// 除霜传感器测量温度
        public int defrost_drain_timer;	    // 除霜排水时间
        public int defrost_lock_timer;      // 除霜后温度锁定计时

        public int door1_timer;             // 门开计时s, <= 0: 门关, 由数据采样模块负责
        public int door1_count;             // 门开计次, 由数据采样模块负责    
        public int humman;                  // 人流量计数

        // 温度报警延迟计时 min
        public int alarm_ad_timer;
        // cat1 心跳计时
        public uint cat1_heart;

        //public ZyStates()
        //{

        //}
    };
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public class ZqmParamsTable
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
        //public char[] name = new char[4];
        public string name;
        public short val;
        public short min;
        public short max;
        public byte unit;
        public byte map;

    }

}
